home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
376-400
/
392
/
spades
/
spades.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-14
|
48KB
|
1,726 lines
/**********************************************************
* PROGRAM: Spades *
* AUTHOR: Gregory M. Stelmack *
* COMPILER: Lattice C V5.04 *
* Copyright (C) 1988 Lattice, Inc. *
* VESRION DATES: *
* Version 1.0 -- February 5, 1990 *
* Version 1.1 -- April 28, 1990 *
* Images used for cards -- file "Spades.images" *
* must be in current directory to run. *
* Title graphics added. New routine for *
* choosing dealer. *
* Tab stops set to 2,4,6,8,... for this listing. *
**********************************************************/
/* Include files */
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <exec/libraries.h>
#include <graphics/gfxmacros.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
/* Structures needed for libraries */
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *DiskfontBase;
/* Intuition Structures */
struct Screen *CustScr;
struct Window *Wdw;
struct Viewport *WVP;
struct IntuiMessage *Message;
/************** Program Constants **************/
#define RP Wdw->RPort /* Raster Port for Graphics Routines */
#define PENS 8 /* Number of Pens */
#define DEPTH 3 /* Number of BitPlanes */
#define MLEFT 1 /* Left Mouse Button Pressed */
#define MRIGHT 2 /* Right Mouse Button Pressed */
#define DIAMONDS 0 /* Suit Definitions */
#define CLUBS 1
#define HEARTS 2
#define SPADES 3
#define WHITE 0xFFF /* Palette Data */
#define RED 0xF00
#define GREEN 0x0F0
#define BLUE 0x00F
#define CYAN 0x0FF
#define PURPLE 0xF0F
#define YELLOW 0xFF0
#define BLACK 0x000
/************** Color Map Data *****************/
static USHORT colormap [PENS] =
{
BLUE, /* Pen 0 */
BLACK, /* Pen 1 */
RED, /* Pen 2 */
GREEN, /* Pen 3 */
WHITE, /* Pen 4 */
YELLOW, /* Pen 5 */
PURPLE, /* Pen 6 */
CYAN /* Pen 7 */
};
#define BLUP 0
#define BLKP 1
#define REDP 2
#define GRNP 3
#define WHTP 4
#define YELP 5
#define PURP 6
#define CYNP 7
/************** Text Structure *****************/
struct TextAttr StdFont =
{
"topaz.font",
TOPAZ_EIGHTY,
FS_NORMAL,
FPF_ROMFONT,
};
/*********** NewScreen Structure **********/
struct NewScreen NewCustScr =
{
0,0, /* Left Edge, Top Edge */
320,200,DEPTH, /* Width, Height, Depth */
WHTP,BLUP, /* Detail Pen, Block Pen */
NULL, /* View Mode */
CUSTOMSCREEN, /* Screen Type */
&StdFont, /* Pointer to Font */
NULL, /* Pointer to Title Text */
NULL, /* Pointer to Screen Gadgets */
NULL, /* Pointer to CustomBitMap */
};
/*********** NewWindow Structure **********/
struct NewWindow NewWdw =
{
0,0, /* Left Edge, Top Edge */
320,200, /* Width, Height */
BLKP,WHTP, /* Block Pen, Detail Pen */
MOUSEBUTTONS | CLOSEWINDOW, /* IDCMP Flags */
SMART_REFRESH | ACTIVATE | GIMMEZEROZERO | RMBTRAP | WINDOWCLOSE,
NULL, /* Pointer to First Gadget */
NULL, /* Pointer to Check Mark image */
"Spades, by Greg Stelmack", /* Title */
NULL, /* Pointer to Screen structure */
NULL, /* Pointer to custom Bit Map */
0,0, /* Minimum Width, Height */
0,0, /* Maximum Width, Height */
CUSTOMSCREEN /* Type of Screen it resides on */
};
/************************* Image Data *************************/
struct Image CardImage =
{
0, 0, /* LeftEdge, TopEdge */
42, 42, 3, /* Width, Height, Depth */
NULL, /* Image Data */
7, 0, /* PlanePick, PlaneOnOff */
NULL /* *NextImage */
};
#include "Spades.h"
/*************************** Arrays ***************************/
/***************************************
* Deck: status of cards. *
* 0 = Undealt or played. *
* 1 thru 4 = Player who holds card. *
***************************************/
int Deck[52] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
/***************************************
* Hand: cards in each player's hand. *
* 0 = Played. *
* 1 thru 52 = Card number. *
***************************************/
int Hand[4][13] = { {0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0} };
/********************************************
* Bid: number of tricks bid by each player. *
********************************************/
int Bid[4] = {0,0,0,0};
/********************************************
* Mode: aggressiveness of each player. *
* The number in this array is added to *
* the strength of the hand to determine *
* the number of tricks to bid. Higher *
* number equals more tricks. *
********************************************/
int Mode[4] = {0,0,0,0};
/********************************************
* SuitPoints: how many points are added to *
* the strength of a hand depending on the *
* number of cards in each suit in the *
* hand. The first row is for non-spades, *
* the second for spades. *
********************************************/
int SuitPoints[2][14] = { {6,3,1,0,0,0,-2,-4,-6,-8,-10,-12,-20,-50},
{-4,-2,-1,0,0,+1,+2,+5,+8,+10,+12,+20,+50} };
/********************************************
* HighCardLeft: the highest unplayed card *
* in each suit. *
********************************************/
int HighCardLeft[4] = {0,0,0,0};
/********************************************
* Card: the card played in a trick by each *
* player. *
********************************************/
int Card[4] = {0,0,0,0};
/********************************************
* Value: the point value of each card held *
* in a hand. Used by computer to determine*
* which card to play. *
********************************************/
int Value[13] = {0,0,0,0,0,0,0,0,0,0,0,0,0};
/********************************************
* SuitNumber: the number of cards in each *
* suit held by a player. *
********************************************/
int SuitNumber[4] = {0,0,0,0};
/********************************************
* CardX & CardY: The X and Y positions for *
* the played card for each player. *
* MsgX & MsgY: The X and Y positions for *
* single character messages for each *
* player. *
********************************************/
int CardX[4] = {100,1,100,209};
int CardY[4] = {99,60,1,60};
int MsgX[4] = {116,45,116,195};
int MsgY[4] = {96,84,50,84};
/********************************************
* OutOfSuit: Whether or not a player is out *
* of a suit. *
********************************************/
BOOL OutOfSuit[4][4] = { {0,0,0,0},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0} };
/******************** Other Global Variables ******************/
char *String = " "; /* Temporary String Storage */
int PlayerScore=0, CompScore=0, PlayerTricks=0, CompTricks=0;
int HandLead=0, Button=0, TrickLead=0, PlayerBid=0, CompBid=0;
int ShortSuit=0, LongSuit=0, HighCard=0, Winner=0;
BOOL SpadePlayed=FALSE, AllDone=FALSE;
char *CardData;
SHORT Mx=0, My=0; /* Mouse Coordinates */
/******************** Function Declarations *******************/
void Spades(), SetUpScreen(), DealCards(), ShowHand(), DrawCard();
int CalcBid(),GetPlayerBid(), TakeTrick(), GetPlayerCard();
int GetCompCard(),FindDealer();
BOOL ValidCard();
void itoa(), PrintBids(), PrintScore(), PrintTricks(), GetBids();
void ReadMouse(), PlayHand(), InitVars(), CalcLead(), CalcFollow();
void FinishRoutine(), WrapUp(), SuggestCard(), CountCards();
void Title();
/********************* Program Begins Here ********************/
/**********************************************************
* Function: main *
* Purpose: Open everything, play the game, close *
* everything. *
**********************************************************/
main()
{
int fh;
unsigned int count=0;
unsigned int length=0;
/* Open the Intuition and Graphics libraries. */
IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library",LIBRARY_VERSION);
if (IntuitionBase == NULL)
{
printf("Can't open Intuition Library");
WrapUp();
}
GfxBase = (struct GfxBase *)
OpenLibrary("graphics.library",LIBRARY_VERSION);
if (GfxBase == NULL)
{
printf("Can't open Graphics Library");
WrapUp();
}
/* Open the screen and window */
if ((NewWdw.Screen = CustScr =
(struct Screen *)OpenScreen(&NewCustScr)) == NULL)
{
printf("Can't open new screen");
WrapUp();
}
if (( Wdw = (struct Window *)OpenWindow(&NewWdw)) == NULL)
{
printf("Can't open new window");
WrapUp();
}
/* Find the viewport and load color map */
WVP = (struct ViewPort *)ViewPortAddress(Wdw);
LoadRGB4(WVP,&colormap,PENS);
/* Seed random number generator with TIMER */
srand(time(NULL));
/* Load Graphic Images */
length=52*126*2*3;
CardData = (char *)AllocMem(length,MEMF_CHIP);
if (!CardData)
{
printf("Could not allocate image memory!");
WrapUp();
}
fh = open("Spades.images",O_RDONLY,0);
if (fh==-1)
{
printf("Can't open images file!");
WrapUp();
}
count = read(fh,CardData,length);
if (count==-1)
{
printf("Error reading images file!");
WrapUp();
}
/* Start Game */
Spades();
/* Close Everything */
WrapUp();
}
/**********************************************************
* Function: WrapUp *
* Parameters: none *
* Return Values: none *
* Purpose: close everything and exit *
**********************************************************/
void WrapUp()
{
if (CardData) FreeMem((char*)CardData,52*126*2);
if (Wdw) CloseWindow(Wdw);
if (CustScr) CloseScreen(CustScr);
if (GfxBase) CloseLibrary(GfxBase);
if (IntuitionBase) CloseLibrary(IntuitionBase);
exit(0);
}
/**********************************************************
* Function: Spades *
* Parameters: None *
* Return Values: None *
* Purpose: Play a game of spades. Loop until someone *
* scores 500. *
**********************************************************/
void Spades()
{
Title();
AllDone=FALSE;
/* Loop until player no longer wants to play. */
while (!AllDone)
{
PlayerScore=CompScore=0;
HandLead=FindDealer();
/* Loop until someone reaches 500 and there is no tie. */
while (((PlayerScore<500)&&(CompScore<500))||(PlayerScore==CompScore))
{
SetUpScreen();
InitVars();
PrintScore();
DealCards();
GetBids();
PrintBids();
PlayHand();
}
FinishRoutine();
}
}
/**********************************************************
* Function: Title *
* Parameters: none *
* Return Values: none *
* Purpose: draw title graphics. *
**********************************************************/
void Title()
{
int i=0;
SetRast(RP,BLUP); /* Clear screen */
SetAPen(RP,YELP);
SetBPen(RP,BLUP);
/* Draw card backs */
for (i=0; i<6 ; i++)
{
DrawImage(RP,&Image25,(i*50)+15,65);
}
/* Flip S */
Delay(5);
DrawImage(RP,&Image24,15,65);
Delay(5);
DrawImage(RP,&Image23,15,65);
Delay(5);
DrawImage(RP,&Image22,15,65);
Delay(5);
DrawImage(RP,&Image21,15,65);
Delay(5);
DrawImage(RP,&Image17,15,65);
Delay(5);
DrawImage(RP,&Image18,15,65);
Delay(5);
DrawImage(RP,&Image19,15,65);
Delay(5);
DrawImage(RP,&Image20,15,65);
/* Flip P */
Delay(5);
DrawImage(RP,&Image24,65,65);
Delay(5);
DrawImage(RP,&Image23,65,65);
Delay(5);
DrawImage(RP,&Image22,65,65);
Delay(5);
DrawImage(RP,&Image21,65,65);
Delay(5);
DrawImage(RP,&Image13,65,65);
Delay(5);
DrawImage(RP,&Image14,65,65);
Delay(5);
DrawImage(RP,&Image15,65,65);
Delay(5);
DrawImage(RP,&Image16,65,65);
/* Flip A */
Delay(5);
DrawImage(RP,&Image24,115,65);
Delay(5);
DrawImage(RP,&Image23,115,65);
Delay(5);
DrawImage(RP,&Image22,115,65);
Delay(5);
DrawImage(RP,&Image21,115,65);
Delay(5);
DrawImage(RP,&Image9,115,65);
Delay(5);
DrawImage(RP,&Image10,115,65);
Delay(5);
DrawImage(RP,&Image11,115,65);
Delay(5);
DrawImage(RP,&Image12,115,65);
/* Flip D */
Delay(5);
DrawImage(RP,&Image24,165,65);
Delay(5);
DrawImage(RP,&Image23,165,65);
Delay(5);
DrawImage(RP,&Image22,165,65);
Delay(5);
DrawImage(RP,&Image21,165,65);
Delay(5);
DrawImage(RP,&Image5,165,65);
Delay(5);
DrawImage(RP,&Image6,165,65);
Delay(5);
DrawImage(RP,&Image7,165,65);
Delay(5);
DrawImage(RP,&Image8,165,65);
/* Flip E */
Delay(5);
DrawImage(RP,&Image24,215,65);
Delay(5);
DrawImage(RP,&Image23,215,65);
Delay(5);
DrawImage(RP,&Image22,215,65);
Delay(5);
DrawImage(RP,&Image21,215,65);
Delay(5);
DrawImage(RP,&Image1,215,65);
Delay(5);
DrawImage(RP,&Image2,215,65);
Delay(5);
DrawImage(RP,&Image3,215,65);
Delay(5);
DrawImage(RP,&Image4,215,65);
/* Flip S */
Delay(5);
DrawImage(RP,&Image24,265,65);
Delay(5);
DrawImage(RP,&Image23,265,65);
Delay(5);
DrawImage(RP,&Image22,265,65);
Delay(5);
DrawImage(RP,&Image21,265,65);
Delay(5);
DrawImage(RP,&Image17,265,65);
Delay(5);
DrawImage(RP,&Image18,265,65);
Delay(5);
DrawImage(RP,&Image19,265,65);
Delay(5);
DrawImage(RP,&Image20,265,65);
/* Prompt for pause */
Move(RP,50,180);
Text(RP,"Click any mouse button...",25);
ReadMouse(); /* Pause for click */
}
/**********************************************************
* Function: FindDealer *
* Parameters: none *
* Return Values: the player determined to initially deal. *
* Purpose: find out who deals first in a game. *
**********************************************************/
int FindDealer()
{
int player=0, card=0, i;
BOOL done=FALSE;
SetRast(RP,BLUP); /* Clear Screen */
SetAPen(RP,YELP);
SetBPen(RP,BLUP);
for (i=0 ; i<52 ; i++) Deck[i]=0; /* Set deck to undealt */
Move(RP,70,70); /* Warn player of what's happening */
Text(RP,"Ace of Spades",13);
Move(RP,98,78);
Text(RP,"deals",5);
while(!done) /* Loop until dealer found */
{
while(Deck[card=rand()%52]) ; /* Find undealt card */
Deck[card]=1; /* Mark card as dealt */
DrawCard(CardX[player],CardY[player],card);
/* Draw card */
Delay(10); /* Pause */
if (card==51) /* Ace of Spades */
{
done=TRUE;
Move(RP,MsgX[player],MsgY[player]);
Text(RP,"*",1);
}
player=(++player)%4; /* Increment player */
}
Move(RP,200,150); /* Wait for player */
Text(RP,"Click mouse",11);
ReadMouse();
SetRast(RP,BLUP);
return((++player)%4); /* Must return player 2 to left of */
/* dealer. Program will later */
/* decrement player to find lead */
/* who should be to left of dealer */
}
/**********************************************************
* Function: SetUpScreen *
* Parameters: none *
* Return Values: none *
* Purpose: gets the screen ready for a new hand. *
**********************************************************/
void SetUpScreen()
{
/* Clear the Screen */
SetRast(RP,BLUP);
/* Draw the Score Box */
SetAPen(RP,YELP);
SetBPen(RP,BLKP);
Move(RP,224,6);
Text(RP," YOU CMP ",11);
Move(RP,224,14);
Text(RP,"SCORE SCORE",11);
Move(RP,224,22);
Text(RP," ",11);
Move(RP,224,30);
Text(RP," BID BID ",11);
Move(RP,224,38);
Text(RP," ",11);
Move(RP,224,46);
Text(RP,"TRICK TRICK",11);
Move(RP,224,54);
Text(RP," ",11);
SetAPen(RP,WHTP);
Move(RP,224,7);
Draw(RP,312,7);
Move(RP,267,0);
Draw(RP,267,55);
}
/**********************************************************
* Function: InitVars *
* Parameters: none *
* Return Values: none *
* Purpose: Initialize variables and arrays for a new hand.*
**********************************************************/
void InitVars()
{
int i;
/* Set Leader */
HandLead=(--HandLead+4)%4;
TrickLead=HandLead;
/* Reset HighCardLeft */
HighCardLeft[0]=12;
HighCardLeft[1]=12;
HighCardLeft[2]=12;
HighCardLeft[3]=12;
/* Reset OutOfSuit */
for (i=0 ; i<4 ; i++)
{
OutOfSuit[i][DIAMONDS]=FALSE;
OutOfSuit[i][CLUBS] =FALSE;
OutOfSuit[i][HEARTS] =FALSE;
OutOfSuit[i][SPADES] =FALSE;
}
/* Determine Modes */
for (i=0 ; i<4 ; i++)
{
Mode[i]=0;
if (i==HandLead) Mode[i]+=2; /* Leader should bid higher */
if (i==0||i==2) /* Human players -- check score */
{
if ((PlayerScore>400)&&(CompScore<350)) Mode[i]-=1;
if (PlayerScore<(CompScore-100)) Mode[i]+=1;
if (PlayerScore<(CompScore-200)) Mode[i]+=1;
if (PlayerScore>(CompScore+100)) Mode[i]-=1;
}
if (i==1||i==3) /* Computer players -- check score */
{
if ((CompScore>400)&&(PlayerScore<350)) Mode[i]-=1;
if (CompScore<(PlayerScore-100)) Mode[i]+=1;
if (CompScore<(PlayerScore-200)) Mode[i]+=1;
if (CompScore>(PlayerScore+100)) Mode[i]-=1;
}
}
}
/**********************************************************
* Function: DealCards *
* Parameters: none *
* Return Values: none *
* Purpose: Shuffle & deal the deck to the players. *
**********************************************************/
void DealCards()
{
int i,j,player,cardnum[4];
for (i=0 ; i<4 ; i++) cardnum[i]=0; /* Reset cards for each player */
for (i=0 ; i<52 ; i++) Deck[i]=0; /* Set whole deck to undealt */
/* Shuffle and Deal Deck */
for (i=0 ; i<52 ; i++)
{
while(Deck[j=rand()%52]) ; /* Find undealt card */
Deck[j]=((i/13)+1); /* Store owning player */
}
/* Transfer cards to player hands */
for (i=0 ; i<52 ; i++)
{
player=Deck[i]-1; /* Get owning player */
Hand[player][cardnum[player]++]=i+1; /* Store card, increment counter */
}
}
/**********************************************************
* Function: ShowHand *
* Parameters: none *
* Return Values: none *
* Purpose: To display the player's hand. *
**********************************************************/
void ShowHand()
{
int i;
/* Erase old hand */
SetAPen(RP,BLUP);
SetOPen(RP,BLUP);
RectFill(RP,21,145,183,186);
/* Draw each card, overlaying part of the previous one */
for (i=0 ; i<13 ; i++)
{
if (Hand[0][i]) /* Only draw if card hasn't been played */
DrawCard(((i*10)+21),145,((Hand[0][i])-1));
}
}
/**********************************************************
* Function: GetBids *
* Parameters: none *
* Return values: none *
* Purpose: Get each player's bid. *
**********************************************************/
void GetBids()
{
int i;
for (i=0 ; i<4 ; i++) Bid[i]=0; /* Reset bids for each player */
/* Loop through each player */
i=HandLead;
do
{
if (i)
Bid[i]=CalcBid(i); /* Computer Player */
else
Bid[i]=GetPlayerBid(); /* Human Player */
i=(++i)%4;
} while (i!=HandLead);
/* Calculate team contracts */
PlayerBid=Bid[0]+Bid[2];
CompBid=Bid[1]+Bid[3];
/* Pause for click */
ReadMouse();
/* Erase Bids */
SetBPen(RP,BLUP);
for (i=0 ; i<4 ; i++)
{
Move(RP,MsgX[i],MsgY[i]);
Text(RP," ",1);
}
}
/**********************************************************
* Function: GetPlayerBid *
* Parameters: none *
* Return Values: bid -- number of tricks bid *
* Purpose: Get the human player's bid. Could use gadgets, *
* but this is easier to program. *
**********************************************************/
int GetPlayerBid()
{
int bid=1,length;
BOOL havebid=FALSE;
ShowHand();
/* Draw input box */
SetAPen(RP,YELP);
SetBPen(RP,BLKP);
Move(RP,258,142);
Text(RP,"BID",3);
Move(RP,250,150);
Text(RP," + ",5);
Move(RP,250,158);
Text(RP," OK",5);
Move(RP,250,166);
Text(RP," - ",5);
/* Loop until OK is clicked */
while(!havebid)
{
/* Draw Current Bid */
SetAPen(RP,GRNP);
SetBPen(RP,BLKP);
Move(RP,250,158);
Text(RP," ",2);
itoa(bid,String);
length=strlen(String);
Move(RP,(258-(4*length)),158);
Text(RP,String,length);
/* Wait for Mouse input */
ReadMouse();
if (Button==MLEFT) /* Left Button Pressed */
{
if ((Mx>265)&&(Mx<274)&&(My>143)&&(My<152)) bid++; /* plus sign */
if ((Mx>273)&&(Mx<290)&&(My>151)&&(My<160)) havebid=TRUE; /* OK */
if ((Mx>265)&&(Mx<274)&&(My>159)&&(My<168)) bid--; /* minus sign */
}
if (Button==MRIGHT) /* Right Button Pressed */
{
bid=CalcBid(0); /* Suggest a Bid */
}
/* Make sure bid is valid */
if (bid<1) bid=1;
if (bid>12) bid=12;
}
/* Erase Input Box */
SetAPen(RP,BLUP);
SetOPen(RP,BLUP);
RectFill(RP,250,135,291,168);
/* Display the bid */
SetAPen(RP,YELP);
SetBPen(RP,BLUP);
itoa(bid,String);
Move(RP,MsgX[0],MsgY[0]);
Text(RP,String,strlen(String));
/* Send the bid back */
return(bid);
}
/**********************************************************
* Function: CalcBid *
* Parameters: player -- number of player to calculate for *
* Return Values: bid -- number of tricks *
* Purpose: To calculate the number of tricks bid by a *
* player. *
**********************************************************/
int CalcBid(player)
int player;
{
int i,j,numsuit,points,suit,bid;
points=0;
/* Add up points for the non-spades suits */
for (i=DIAMONDS ; i<SPADES ; i++) /* Loop thru suits */
{
numsuit=0;
suit=i*13;
/* Count cards for suit and add appropriate points */
for (j=0 ; j<13 ; j++)
{
if (Deck[suit+j]==player+1) numsuit++;
}
points+=SuitPoints[0][numsuit];
/* Add points for face cards */
if (Deck[suit+12]==player+1) points+=4; /* Ace */
if (Deck[suit+11]==player+1) points+=3; /* King */
if (Deck[suit+10]==player+1) points+=2; /* Queen */
}
/* Calculate spades */
numsuit=0;
/* Count Spades and add appropriate points */
for (j=39 ; j<52 ; j++)
{
if (Deck[j]==player+1) numsuit++;
}
points+=SuitPoints[1][numsuit];
/* Add points for Face Cards */
if (Deck[51]==player+1) points+=4; /* Ace */
if (Deck[50]==player+1) points+=3; /* King */
if (Deck[49]==player+1) points+=2; /* Queen */
if (Deck[48]==player+1) points+=1; /* Jack */
points+=Mode[player]; /* Adjust for aggressiveness */
if (points<4) points=4; /* Validate number of points */
bid=points/4; /* Find Bid */
/* Make sure total team bid not greater than 13 */
i=(player+2)%4; /* Find partner */
if ((bid+Bid[i])>13) bid=13-Bid[i];
/* Display Bid */
itoa(bid,String);
SetAPen(RP,YELP);
SetBPen(RP,BLUP);
Move(RP,MsgX[player],MsgY[player]);
Text(RP,String,strlen(String));
/* Send bid back */
return(bid);
}
/**********************************************************
* Function: PlayHand *
* Parameters: none *
* Return Values: none *
* Purpose: Play out a hand until all 13 tricks are taken. *
**********************************************************/
void PlayHand()
{
int i;
/* Initialize */
PlayerTricks=CompTricks=0;
SpadePlayed=FALSE;
PrintTricks();
/* Loop through all 13 tricks */
for (i=0 ; i<13 ; i++)
{
TrickLead=TakeTrick(); /* Play a trick */
if ((TrickLead==0)||(TrickLead==2)) /* Who won? */
PlayerTricks++;
else
CompTricks++;
PrintTricks(); /* Display new trick total */
/* Indicate who won with an '*' */
SetAPen(RP,YELP);
SetBPen(RP,BLUP);
Move(RP,MsgX[TrickLead],MsgY[TrickLead]);
Text(RP,"*",1);
/* Pause for click */
ReadMouse();
/* Erase winner indicator */
Move(RP,MsgX[TrickLead],MsgY[TrickLead]);
Text(RP," ",1);
}
/* Calculate new score */
if (PlayerTricks<PlayerBid)
PlayerScore-=(10*PlayerBid);
if (CompTricks<CompBid)
CompScore-=(10*CompBid);
if (PlayerTricks>=PlayerBid)
PlayerScore+=((10*PlayerBid)+(PlayerTricks-PlayerBid));
if (CompTricks>=CompBid)
CompScore+=((10*CompBid)+(CompTricks-CompBid));
/* Pause for click */
ReadMouse();
}
/**********************************************************
* Function: TakeTrick *
* Parameters: none *
* Return Values: winner of trick *
* Purpose: Each player plays a card, then determine trick *
* winner. *
**********************************************************/
int TakeTrick()
{
int i,j,leadsuit,suit,value;
/* Clear previously played cards */
SetAPen(RP,BLUP);
SetOPen(RP,BLUP);
for (i=0 ; i<4 ; i++) RectFill(RP,CardX[i],CardY[i],(CardX[i]+41),(CardY[i]+41));
/* Get played cards */
i=TrickLead;
do
{
if (!i)
Card[i]=GetPlayerCard();
else
Card[i]=GetCompCard(i);
if (i==TrickLead) /* First card played wins so far */
{
HighCard=Card[i];
leadsuit=Card[i]/13;
Winner=i;
}
else
{
suit=Card[i]/13;
/* See if this card is the new winner */
if (((suit==leadsuit)||(suit==SPADES))&&(Card[i]>HighCard))
{
HighCard=Card[i];
Winner=i;
}
/* Was player out of the lead suit ? */
if (suit!=leadsuit) OutOfSuit[i][leadsuit]=TRUE;
}
i=(++i)%4;
} while (i!=TrickLead);
ShowHand();
/* Set highest card played in each suit */
for (i=0 ; i<4 ; i++)
{
for (j=0 ; j<4 ; j++) /* Need two loops to make sure we get all */
{
value=Card[j]%13;
suit=Card[j]/13;
if (value==HighCardLeft[suit]) HighCardLeft[suit]=value-1;
}
}
/* Send back trick winner */
return(Winner);
}
/**********************************************************
* Function: GetPlayerCard *
* Parameters: none *
* Return Values: card picked to play *
* Purpose: Allow player to pick card to play. *
**********************************************************/
int GetPlayerCard()
{
int i,x,card;
/* Let player know that it's his/her turn */
SetBPen(RP,BLUP);
SetAPen(RP,YELP);
Move(RP,200,150);
Text(RP,"PLAY A CARD",11);
/* Loop until we get a good card */
FOREVER
{
ReadMouse(); /* Wait for mouse click */
if (Button==MRIGHT) SuggestCard(); /* Player wants a suggestion */
if (Button==MLEFT) /* Did player pick a card ? */
{
for (i=12 ; i>=0 ; i--) /* Check from right to left */
{
x=(i*10)+21; /* Set left corner for card */
/* See if clicked inside this card and if card is still unplayed */
if ((My<187)&&(My>144)&&(Mx<(x+42))&&(Mx>=x)&&(Hand[0][i]))
{
if (ValidCard(i)) /* Was this a playable card ? */
{
card=Hand[0][i]-1;
Hand[0][i]=0; /* Mark card as played */
if ((card/13)==SPADES) SpadePlayed=TRUE; /* Spades have been broken */
/* Erase suggestion '*' */
SetAPen(RP,BLUP);
SetOPen(RP,BLUP);
RectFill(RP,21,136,170,144);
DrawCard(CardX[0],CardY[0],card); /* Draw played card */
/* Erase prompt message */
SetBPen(RP,BLUP);
Move(RP,200,150);
Text(RP," ",11);
/* Send back played card */
return(card);
}
else
/* if chosen card was not valid, need a new card */
i=-1;
}
}
}
}
}
/**********************************************************
* Function: ValidCard *
* Parameters: card -- card in player's hand to check *
* Return Values: was card valid or not? *
* Purpose: To determine if the card chosen by the player *
* was valid or not. *
**********************************************************/
BOOL ValidCard(card)
int card;
{
int i,suit,leadsuit;
SuitNumber[DIAMONDS]=0;
SuitNumber[CLUBS] =0;
SuitNumber[HEARTS] =0;
SuitNumber[SPADES] =0;
/* Count number of cards player has in each suit */
for (i=0 ; i<13 ; i++)
{
if (Hand[0][i]) SuitNumber[(Hand[0][i]-1)/13]++;
}
suit=(Hand[0][card]-1)/13; /* Find suit of played card */
if (!TrickLead) /* Player is leading */
{
/* If he didn't lead a spade, it was a good play */
if (suit!=SPADES) return(TRUE);
/* If he only has spades, he has no choice */
if ((!SuitNumber[0])&&(!SuitNumber[1])&&(!SuitNumber[2])) return(TRUE);
/* If spades have been played, he can lead anything */
if (SpadePlayed) return(TRUE);
/* Must have lead a spade when it was illegal to */
return(FALSE);
}
/* Player doesn't lead */
leadsuit=Card[TrickLead]/13; /* Find suit that was lead */
/* If he played the suit that was lead, he is OK */
if (suit==leadsuit) return(TRUE);
/* If he didn't have any, he's OK */
if (!SuitNumber[leadsuit]) return(TRUE);
/* Must have had some but didn't play them */
return(FALSE);
}
/**********************************************************
* Function: CountCards *
* Parameters: none *
* Return Values: none *
* Purpose: Count cards in each suit for a player. *
* Determine short and long suits. *
**********************************************************/
void CountCards(player)
int player;
{
int i,card,suit,maximum,minimum;
/* Initialization */
SuitNumber[DIAMONDS]=0;
SuitNumber[CLUBS] =0;
SuitNumber[HEARTS] =0;
SuitNumber[SPADES] =0;
/* Loop through all cards in the player's hand */
for (i=0 ; i<13 ; i++)
{
if (Hand[player][i]) /* Make sure card hasn't been played */
{
card=Hand[player][i]-1;
suit=card/13;
Value[i]=6-(card%13); /* Give lower cards a slight priority */
SuitNumber[suit]++; /* Count Number of Suit held */
}
else
Value[i]=-10000; /* Don't throw previously played cards */
}
/* Find short and long suits */
minimum=14;
maximum=0;
ShortSuit=LongSuit=3;
for (i=DIAMONDS ; i<SPADES ; i++)
{
if ((SuitNumber[i]<minimum)&&(SuitNumber[i]>0))
{
minimum=SuitNumber[i];
ShortSuit=i;
}
if (SuitNumber[i]>maximum)
{
maximum=SuitNumber[i];
LongSuit=i;
}
}
}
/**********************************************************
* Function: SuggestCard *
* Parameters: none *
* Return Values: none *
* Purpose: Suggest a card for player to play. *
**********************************************************/
void SuggestCard()
{
int i,pick,maximum;
CountCards(0);
/* Go to appropriate point calculating routine */
if (!TrickLead)
CalcLead(0);
else
CalcFollow(0);
/* Find best card (the one with the most points) */
pick=0;
maximum=Value[0];
for (i=1 ; i<13 ; i++)
{
if (Value[i]>maximum)
{
maximum=Value[i];
pick=i;
}
}
/* Display an '*' over suggested card */
SetAPen(RP,YELP);
SetBPen(RP,BLUP);
Move(RP,((pick*10))+22,142);
Text(RP,"*",1);
}
/**********************************************************
* Function: GetCompCard *
* Parameters: player -- player to play *
* Return Values: card played *
* Purpose: Determine which card a computer-controlled *
* player will play. *
**********************************************************/
int GetCompCard(player)
int player;
{
int i,pick,card,maximum;
CountCards(player);
/* Go to appropriate point calculating routine */
if (player==TrickLead)
CalcLead(player);
else
CalcFollow(player);
/* Find best card (the one with the most points) */
pick=0;
maximum=Value[0];
for (i=1 ; i<13 ; i++)
{
if (Value[i]>maximum)
{
maximum=Value[i];
pick=i;
}
}
card=Hand[player][pick]-1;
if ((card/13)==3) SpadePlayed=TRUE; /* Mark that spades have been broken */
Hand[player][pick]=0; /* Card has now been played */
DrawCard(CardX[player],CardY[player],card); /* Draw the played card */
return(card); /* Send the played card back */
}
/**********************************************************
* Function: CalcLead *
* Parameters: player -- whose hand to calculate *
* Return Values: none *
* Purpose: To calculate the value of each card in a hand *
* to determine which card should be played if *
* the hand is leading. *
**********************************************************/
void CalcLead(player)
int player;
{
int i,card,suit,value;
BOOL opponentsout=FALSE, partnerout=FALSE;
/* Loop through all cards in hand */
for (i=0 ; i<13 ; i++)
{
if (Hand[player][i]) /* Make sure card hasn't been played */
{
/* Find suit and face value */
card=Hand[player][i]-1;
suit=card/13;
value=card%13;
if ((OutOfSuit[(player+1)%4][suit])||(OutOfSuit[(player+3)%4][suit]))
opponentsout=TRUE;
if (OutOfSuit[(player+2)%4][suit])
partnerout=TRUE;
if (value==HighCardLeft[suit]) /* Card is highest left in a suit */
{
if (suit==SPADES) /* Spades don't matter if someone is */
Value[i]+=50; /* out. */
else
{
if (opponentsout) /* If opponents are out, don't waste */
Value[i]-=50; /* high cards. */
else
Value[i]+=50;
}
}
/* If player holds spades, get rid of short suit */
if ((SuitNumber[SPADES])&&(suit==ShortSuit)) Value[i]+=250;
/* If player doesn't hold spades, get rid of long suit */
if ((!SuitNumber[SPADES])&&(suit==LongSuit)) Value[i]+=250;
/* If spades aren't broken, they can't be lead */
if ((suit==SPADES)&&(!SpadePlayed)) Value[i]-=5000;
/* Lead suits your partner is out of */
if ((suit!=SPADES)&&(partnerout)&&(!opponentsout)) Value[i]+=300;
}
}
}
/**********************************************************
* Function: CalcFollow *
* Parameters: player -- whose hand to calculate *
* Return Values: none *
* Purpose: To calculate the value of each card in a hand *
* to determine which card should be played if *
* the hand is not leading. *
**********************************************************/
void CalcFollow(player)
int player;
{
int i,card,suit,value,leadsuit;
BOOL alreadywon;
leadsuit=Card[TrickLead]/13; /* Calculate the suit that was lead */
/* See if partner has already won the trick */
alreadywon=FALSE;
/* See if win is guaranteed (player is last to play) */
if ((Winner==((player+2)%4))&&(TrickLead==((player+1)%4)))
alreadywon=TRUE;
/* See if win is probable (player is next to last to play) */
if ((Winner==TrickLead)&&(TrickLead==((player+2)%4)))
{
value=Card[TrickLead]%13;
if ((value==HighCardLeft[leadsuit])&&(value>9)) alreadywon=TRUE;
}
/* Loop through all cards in hand */
for (i=0 ; i<13 ; i++)
{
if (Hand[player][i]) /* Make sure card hasn't been played */
{
/* Find suit and face value of card */
card=Hand[player][i]-1;
suit=card/13;
value=card%13;
if (suit==leadsuit) /* Card is of lead suit */
{
Value[i]+=5000;
/* If it is the highest one left in that suit, throw it */
if ((value==HighCardLeft[suit])&&(TrickLead!=((player+1)%4))&&(card>HighCard))
Value[i]+=70;
/* See if card will beat those previously played */
if (card>HighCard)
{
if (!alreadywon) /* Team hasn't won yet */
{
if (TrickLead==((player+1)%4)) /* Can definitely take trick */
Value[i]+=100;
else
Value[i]+=10; /* Maybe take trick */
}
else
Value[i]-=75; /* If the team has one, hold high cards */
}
/* If team has already one the trick, throw low cards */
if ((card<HighCard)&&alreadywon) Value[i]+=75;
}
/* If player is going to throw a spade, make sure it has a chance of
winning */
if ((suit==SPADES)&&(card>HighCard))
{
if (!alreadywon)
Value[i]+=10; /* If team hasn't won, throw the spade */
else
Value[i]-=1000; /* If team has won, hold high spades */
}
if ((suit==SPADES)&&(card<HighCard))
{
if (!alreadywon)
Value[i]-=1000; /* If the team hasn't won, don't throw a losing spade */
else
Value[i]+=10; /* If the team has one, throw a low spade */
}
/* If player is out of the lead suit, don't throw important cards
in other suits */
if ((suit!=leadsuit)&&(value==HighCardLeft[suit])) Value[i]-=100;
/* If player is out of lead suit, let's see about trumping */
if ((!SuitNumber[leadsuit])&&(suit==SPADES))
{
if (!alreadywon)
Value[i]+=100; /* If team hasn't won, trump */
else
Value[i]-=1000; /* If team has won, no need to trump */
}
/* If player is out of lead suit and out of spades, throw the long
suit left (keep as many suits as possible in hand) */
if ((!SuitNumber[leadsuit])&&(!SuitNumber[SPADES])&&(suit==LongSuit))
{
Value[i]+=100;
}
/* Give short suit a priority */
if (suit==ShortSuit) Value[i]+=45;
}
}
}
/**********************************************************
* Function: PrintBids *
* Parameters: none *
* Return Values: none *
* Purpose: Display the number of tricks bid by each team *
* in the score box. *
**********************************************************/
void PrintBids()
{
int length=0;
SetAPen(RP,GRNP);
SetBPen(RP,BLKP);
itoa(PlayerBid,String);
length=strlen(String);
Move(RP,(244-(4*length)),38);
Text(RP,String,length);
itoa(CompBid,String);
length=strlen(String);
Move(RP,(292-(4*length)),38);
Text(RP,String,length);
}
/**********************************************************
* Function: PrintScore *
* Parameters: none *
* Return Values: none *
* Purpose: Display each team's score in the score box. *
**********************************************************/
void PrintScore()
{
int length=0;
SetAPen(RP,GRNP);
SetBPen(RP,BLKP);
itoa(PlayerScore,String);
length=strlen(String);
Move(RP,(244-(4*length)),22);
Text(RP,String,length);
itoa(CompScore,String);
length=strlen(String);
Move(RP,(292-(4*length)),22);
Text(RP,String,length);
}
/**********************************************************
* Function: PrintTricks *
* Parameters: none *
* Return Values: none *
* Purpose: Display the number of tricks taken by each *
* team in the score box. *
**********************************************************/
void PrintTricks()
{
int length=0;
SetAPen(RP,GRNP);
SetBPen(RP,BLKP);
itoa(PlayerTricks,String);
length=strlen(String);
Move(RP,(244-(4*length)),54);
Text(RP,String,length);
itoa(CompTricks,String);
length=strlen(String);
Move(RP,(292-(4*length)),54);
Text(RP,String,length);
}
/**********************************************************
* Function: ReadMouse *
* Parameters: none *
* Return Values: none *
* Purpose: Wait for mouse input, and update the mouse *
* variables accordingly. *
**********************************************************/
void ReadMouse()
{
ULONG class;
USHORT code;
BOOL gotmouse=FALSE;
/* Loop until we have a mouse message */
while(!gotmouse)
{
/* Wait for Intuition Message */
if ((Message=(struct IntuiMessage *) GetMsg(Wdw->UserPort)) == NULL)
{
Wait(1L<<Wdw->UserPort->mp_SigBit);
continue;
}
/* Interpret Message */
class = Message->Class;
code = Message->Code;
Mx=((SHORT) Message->MouseX) - 4; /* Adjustments for */
My=((SHORT) Message->MouseY) - 12; /* GIMMEZEROZERO Window */
/* See if Window Close Box clicked */
if (class & CLOSEWINDOW) WrapUp();
/* Otherwise, make sure Message was caused by mouse */
if (class & MOUSEBUTTONS)
{
switch(code)
{
/* Left Button Released */
case SELECTUP:
Button=MLEFT;
gotmouse=TRUE;
break;
/* Right Button Released */
case MENUUP:
Button=MRIGHT;
gotmouse=TRUE;
break;
/* Other Input */
default:
gotmouse=FALSE;
}
}
ReplyMsg(Message);
}
}
/**********************************************************
* Function: DrawCard *
* Parameters: x -- x coordinate of top left corner *
* y -- y coordinate of top left corner *
* card -- number of card to draw *
* Return Values: none *
* Purpose: Draw a card. *
**********************************************************/
void DrawCard(x, y, card)
int x, y, card;
{
CardImage.ImageData = (UWORD *)(CardData+card*126*6);
DrawImage(RP, &CardImage, x, y);
}
/**********************************************************
* Function: FinishRoutine *
* Parameters: none *
* Return Values: none *
* Purpose: Display final score, ask to play again. *
**********************************************************/
void FinishRoutine()
{
BOOL haveinput;
SetRast(RP,BLUP);
SetAPen(RP,WHTP);
SetBPen(RP,BLUP);
Move(RP,112,56);
Text(RP,"FINAL SCORE:",12);
Move(RP,80,72);
Text(RP,"YOU:",4);
Move(RP,184,72);
Text(RP,"ME:",3);
SetAPen(RP,YELP);
itoa(PlayerScore,String);
Move(RP,116,72);
Text(RP,String,strlen(String));
itoa(CompScore,String);
Move(RP,212,72);
Text(RP,String,strlen(String));
Move(RP,112,96);
Text(RP,"PLAY AGAIN ?",12);
SetAPen(RP,BLKP);
SetBPen(RP,WHTP);
Move(RP,112,112);
Text(RP,"YES",3);
Move(RP,188,112);
Text(RP,"NO",2);
haveinput=FALSE;
while (!haveinput)
{
ReadMouse();
if ((Mx>111)&&(Mx<136)&&(My>105)&&(My<114))
{
haveinput=TRUE;
AllDone=FALSE;
}
if ((Mx>187)&&(Mx<204)&&(My>105)&&(My<114))
{
haveinput=TRUE;
AllDone=TRUE;
}
}
}
/**********************************************************
* Function: itoa *
* Parameters: n -- number to convert *
* s -- pointer to result string *
* Return Values: none *
* Purpose: Convert an integer to a string so it can be *
* used by the Text function. Lattice does not *
* have one. *
**********************************************************/
void itoa(n,s)
char *s;
int n;
{
int i=0;
BOOL sign=FALSE;
if (n<0)
{
sign=TRUE;
n=-n;
}
do
{
s[i++]=n%10+'0';
} while((n/=10)>0);
if (sign) s[i++]='-';
s[i]='\0';
strrev(s);
}